/****************************************************************************

Force Engine v0.5

Creado: 23/03/09
Clase: Node.cpp
Hecho by: German Battiston AKA Melkor

****************************************************************************/

//---------------------------------------------------------------------------
#include "Node.h"
//---------------------------------------------------------------------------
Node::Node(Graphics &rkGraphics)
:
INode(rkGraphics)
{
	m_iType = TYPE_INNER_NODE;
}
//---------------------------------------------------------------------------
Node::~Node()
{
	m_pkParent = NULL;

	if(m_pkBoundingVolume)
	{
		delete m_pkBoundingVolume;
		m_pkBoundingVolume = NULL;
	}

	for(unsigned int i = 0; i < m_vChildren.size(); i ++)
	{
		if(m_vChildren[i])
		{
			delete m_vChildren[i];
		}
	}

	m_vChildren.clear();
}
//---------------------------------------------------------------------------
bool Node::Initialize(std::string szName, INode * pkParentNode)
{
	if(pkParentNode != NULL)
	{
		m_iType = TYPE_INNER_NODE;

		if(!((Node*)pkParentNode)->AddChildNode(this))
		{
			return false;
		}
	}
	else
	{
		m_iType = TYPE_ROOT_NODE;
	}

	m_kName = szName;

	return true;
}
//---------------------------------------------------------------------------
const BVH * Node::Update()
{
	const BVH * pkTmpBVH = NULL;
	D3DXMatrixIdentity(&m_kMatWorldTransform);
	if(m_bNeedUpdate && m_pkParent)
	{
		D3DXMatrixMultiply(&m_kMatWorldTransform, &m_kMatLocalTransform, m_pkParent->GetWorldTransform());
	}
	else
	{
		memcpy((void*)&m_kMatWorldTransform,(void*)m_kMatLocalTransform,sizeof(D3DXMATRIX));
	}

	if(!m_vChildren.empty())
	{

		// chequeo de BVH
		bool bFirstCheck = true;

		unsigned int uiChildrenSize = (unsigned int)m_vChildren.size();

		for(unsigned int i = 0; i < uiChildrenSize; i++)
		{
			if(m_bNeedUpdate)
			{
				m_vChildren[i]->m_bNeedUpdate = m_bNeedUpdate;
			}

			if(m_vChildren[i]->m_bNeedUpdate)
			{
				pkTmpBVH = m_vChildren[i]->Update();
				if(pkTmpBVH != NULL)
				{
					if(bFirstCheck)	// si es el primer bvh cambiado tomo su bvh como base
					{
						bFirstCheck = false;
						
						m_pkBoundingVolume->CopyFromBVH(pkTmpBVH);
						
						if(i > 0) // si no es el primer hijo vuelvo hacia atras incrementando el bvh segun corresponda
						{
							for(int j = (i-1); j > -1; j--)
							{
								m_pkBoundingVolume->UpdateBVH(&(m_vChildren[j]->GetBVH()->m_kMin),
															  &(m_vChildren[j]->GetBVH()->m_kMax));
							}
						}
					}
					else // si no es el primer bvh cambiado, incremento el bvh segun corresponda, recorriendo hacia adelante
					{
						m_pkBoundingVolume->UpdateBVH(&(pkTmpBVH->m_kMin), &(pkTmpBVH->m_kMax));
					}
					
				}
				m_vChildren[i]->m_bNeedUpdate = false;
			}
			else
			{
				m_pkBoundingVolume->UpdateBVH(&(m_vChildren[i]->m_pkBoundingVolume->m_kMin),
											  &(m_vChildren[i]->m_pkBoundingVolume->m_kMax));
			}
		}
		
	}
	
	m_bNeedUpdate = false;

	if(m_pkBoundingVolume->IsInsideBoundaries())
	{
		return NULL;
	}
	else
	{
		return m_pkBoundingVolume;
	}
	
}
//---------------------------------------------------------------------------
bool Node::AddChildNode(INode * pkChildNode)
{
	if(pkChildNode != NULL)
	{
		if( (pkChildNode->GetParentNode() != NULL) || (pkChildNode->IsRootNode()) )
		{
			return false;
		}

		pkChildNode->SetParentNode(this);
		m_vChildren.push_back(pkChildNode);

		m_pkBoundingVolume->UpdateBVH(&(pkChildNode->m_pkBoundingVolume->m_kMin),
									  &(pkChildNode->m_pkBoundingVolume->m_kMax));
		
		return true;
	}
	
	return false;
}
//---------------------------------------------------------------------------
void Node::RemoveChildNode(INode * pkChildNode)
{
	std::vector<INode*>::iterator it;

	if(pkChildNode != NULL && !m_vChildren.empty())
	{
		for(it = m_vChildren.begin(); it != m_vChildren.end(); it++)
		{
			if(*it == pkChildNode)
			{
				m_vChildren.erase(it);

				break;
			}
		}
	}
}
//---------------------------------------------------------------------------
int Node::CountLowerNodes()
{
	int iRetval = (int)m_vChildren.size();

	for(unsigned int i = 0; i < m_vChildren.size(); i++)
	{
		iRetval += m_vChildren[i]->CountLowerNodes();
	}

	return iRetval;
}
//---------------------------------------------------------------------------
void Node::SetName(std::string szName)
{
	m_kName = szName;
}

//---------------------------------------------------------------------------
INode * Node::GetNodeByName(const char* szSearchName)
{
	if(strcmp(m_kName.c_str(),szSearchName) == 0)
		return this;

	INode * kReturnNode = NULL;

	for(unsigned int i = 0; i < m_vChildren.size(); i++)
	{
		kReturnNode = m_vChildren[i]->GetNodeByName(szSearchName);

		if((kReturnNode != NULL))
		{
			return kReturnNode;
			break;
		}
	}

	return NULL;
}
//---------------------------------------------------------------------------
void Node::Draw()
{
	//m_pkBoundingVolume->Draw();
}
//---------------------------------------------------------------------------